package tv.acgn.advertisement.search.index.impl;

import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import tv.acgn.advertisement.search.exception.AbstractAdSearchException;
import tv.acgn.advertisement.search.exception.IndexUpdateUnSupportException;
import tv.acgn.advertisement.search.index.IndexAware;
import tv.acgn.advertisement.search.indexobejct.UnitInterestIO;

/**
 * @author : junG
 * @program : advertisement-ad-search-index
 * @description : 推广单元-关键词索引操作实现类
 * @date : 2019-07-07 23:26
 **/

@Service
@Slf4j
public class UnitKeywordIndexImpl  implements IndexAware<String, Set<String>> {

    /**
     * 推广计划关键词->推广单元 的索引
     */
    private static Map<String, Set<String>> keywordUnitMap=new ConcurrentHashMap<>();

    /**
     * 推广单元->推广计划关键词 的索引
     */
    private static Map<String, Set<String>> unitKeywordMap=new ConcurrentHashMap<>();

    /**
     * <h2>通过索引的键获取值</h2>
     *
     * @param key [1] 键
     *
     * @return {@link Set<String>} 值对象
     *
     * @throws AbstractAdSearchException 异常
     * @author junG
     * @description 通过索引的键获取值
     * @date 22:31 2019/6/30
     */
    @Override
    public Set<String> get(String key) throws AbstractAdSearchException {
        return Optional.ofNullable(keywordUnitMap.get(key))
            .orElseGet(Collections::emptySet);
    }

    /**
     * <h2>新增一条索引</h2>
     *
     * @param key       [1] 键 这里是推广计划关键词 keyword
     * @param unitIds [2] 值对象 这里是推广计划关键词对应的推广计划识别码集合
     *
     * @return {@link Void}
     *
     * @throws AbstractAdSearchException 异常
     * @author junG
     * @description 新增一条索引
     * @date 22:32 2019/6/30
     */
    @Override
    @SuppressWarnings({"Duplicates"})
    public void add(String key, Set<String> unitIds) throws AbstractAdSearchException {
        /**
         * 先添加 推广计划关键词->推广单元 的索引
         */
        Set<String> unitIdSet=keywordUnitMap.computeIfAbsent(key,k-> (new ConcurrentSkipListSet<>()));

        unitIdSet.addAll(unitIds);
        /**
         * 再添加 推广单元->推广计划关键词 的索引
         */
        unitIds.forEach(id->{
            Set<String> keywordSet=unitKeywordMap.computeIfAbsent(id,k-> (new ConcurrentSkipListSet<>()));
            keywordSet.add(key);
        });
    }

    /**
     * <h2>更新索引键对应的索引值对象</h2>
     *
     * @param s       [1]
     * @param strings [2]
     *
     * @return {@link Void}
     *
     * @throws AbstractAdSearchException 异常
     * @author junG
     * @description 更新索引键对应的索引值对象
     * @date 22:35 2019/6/30
     */
    @Override
    public void update(String s, Set<String> strings) throws AbstractAdSearchException {
        log.error("推广计划关键词索引不自持更新");
        throw new IndexUpdateUnSupportException(UnitInterestIO.class);
    }

    /**
     * <h2>删除索引对象</h2>
     * 关键词的索引删除不适用此方法
     * 请使用
     * @see UnitKeywordIndexImpl#deleteUnitId(java.lang.String, java.util.Set)
     * @see UnitKeywordIndexImpl#deleteKeyword(java.lang.String)
     */
    @Override
    @Deprecated
    public void delete(String keyword) throws AbstractAdSearchException {


    }

    /**
     * <h2>删除索引对象的推广单元关键词对应的推广单元识别码 UnitId</h2>
     *
     * @param keyword [1] 推广单元关键词
     * @param unitIds [2] 推广单元识别码集合
     *
     * @return {@link Void}
     *
     * @throws AbstractAdSearchException 异常
     * @author junG
     * @description 删除 推广单元关键词keyword到推广单元识别码UnitId的索引对象关系
     * @date 19:22 2019/7/14
     */
    public void deleteUnitId(String keyword,Set<String> unitIds) throws AbstractAdSearchException {
        /*
            根据关键词找到对应的推广单元集合 然后删除掉对应的推广单元
         */
        Optional.ofNullable(keywordUnitMap.get(keyword))
            .ifPresent(x->x.removeAll(unitIds));

        /*
         * 遍历推广单元->关键词索引 删除此推广单元
         */
        unitIds.forEach(id->{
            unitKeywordMap.remove(id);
        });
    }

    /**
     * <h2>删除推广单元关键词</h2>
     * @author junG
     * @description 删除推广单元关键词
     * @date 19:24 2019/7/14
     * @param keyword [1] 关键词
     * @return {@link Void}
     * @throws  异常
     */
    public void deleteKeyword(String keyword) throws AbstractAdSearchException {
        log.info("删除索引对象keywordUnitMap的关键词 keyword={}", keyword);
        /*
         * 关键词表删除关键词
         */
        keywordUnitMap.remove(keyword);

        /*
         * 推广单元索引表同时删除指向关键词的关系
         */
        unitKeywordMap.forEach((k, v) -> {
            log.info("删除索引对象UnitKeyword的推广单元->关键词关系 keyword={}",keyword);
            v.remove(keyword);
        });
    }
}
